package org.sample.junit5.ex7;

import org.junit.jupiter.api.extension.*;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.concurrent.TimeUnit;

public class TimingExtension implements BeforeTestExecutionCallback, AfterTestExecutionCallback, ParameterResolver {

    private static final String START_TIME = "start.time.ns";

    private ExtensionContext.Namespace ns(ExtensionContext context) {
        return ExtensionContext.Namespace.create(getClass(), context.getRequiredTestMethod());
    }

    @Override
    public void beforeTestExecution(ExtensionContext context) {
        context.getStore(ns(context)).put(START_TIME, System.nanoTime());
    }

    @Override
    public void afterTestExecution(ExtensionContext context) {
        long start = context.getStore(ns(context)).remove(START_TIME, long.class);
        long durationNs = System.nanoTime() - start;
        System.out.printf("[TimingExtension] %s.%s 耗时: %d ms%n",
                context.getRequiredTestClass().getSimpleName(),
                context.getRequiredTestMethod().getName(),
                TimeUnit.NANOSECONDS.toMillis(durationNs));
    }

    /**
     * 参数解析：为带 @TestMethodName 且类型为 String 的参数注入测试方法名
     */
    @Override
    public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext)
            throws ParameterResolutionException {
        return parameterContext.isAnnotated(TestMethodName.class)
                && parameterContext.getParameter().getType().equals(String.class);
    }

    @Override
    public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext)
            throws ParameterResolutionException {
        return extensionContext.getRequiredTestMethod().getName();
    }

    /**
     * 自定义参数注解
     */
    @Target(ElementType.PARAMETER)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface TestMethodName {
    }
}